<html>
<head>
  <title>select</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="Evernote Windows/307027 (zh-CN, DDL); Windows/6.1.0 (Win32);"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="626"/>
<h1>select</h1>

<div>
<span><div><h1>Waiting for I/O completion</h1><div><span style="line-height: 1.45;"><font style="font-size: 16pt; color: rgb(28, 51, 135);"><b>多路复用I/O</b></font></span><br/></div><div><br/></div><div><span style="-en-paragraph: true;">设备的文件的资源如果可用（可读或者可写）则会通知进程，反之则会让进程睡眠，等到数据到来可用的时候，再唤醒进程。</span></div><div><span style="-en-paragraph: true;"><br/></span></div><div><span style="-en-paragraph: true;">这些设备的文件描述符被放在一个数组中，然后</span><span style="-en-paragraph: true;">select</span><span style="-en-paragraph: true;">调用的时候遍历这个数组，如果对于的文件描述符可读则会返回改文件描述符。当遍历结束之后，如果仍然没有一个可用设备文件描述符，</span><span style="-en-paragraph: true;">select</span><span style="-en-paragraph: true;">让用户进程则会睡眠，直到等待资源可用的时候在唤醒，遍历之前那个监视的数组。每次遍历都是线性的。</span></div><div><br/></div><h3><font color="#1C3387" style="font-size: 16pt;">select 回显服务器</font></h3><div>select涉及系统调用和操作系统相关的知识，使用python的select模块很容易写出下面一个回显服务器：</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>import select</div><div>import socket</div><div>import sys</div><div><br/></div><div>HOST = 'localhost'</div><div>PORT = 5000</div><div>BUFFER_SIZE = 1024</div><div><br/></div><div>server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</div><div>server.bind((HOST, PORT))</div><div>server.listen(5)</div><div><br/></div><div>inputs = [server, sys.stdin]</div><div>running = True</div><div><br/></div><div>while True:<span>    </span></div><div><span>    try:</span><br/></div><div><span><span>    <span>    # 调用select函数， 阻塞等待</span></span><br/></span></div><div><span><span>    <span>    readable, writeable, exceptional = select.select(inputs, [], [])</span></span><br/></span></div><div><span><span>    except select.error, e:</span><br/></span></div><div><span><span>    <span>    break</span></span><br/></span></div><div><span><br/></span></div><div><span><span>    # 数据抵达，循环</span><br/></span></div><div><span><span>    for sock in readable:</span><br/></span></div><div><span><span>    <span>    # 建立连接</span></span><br/></span></div><div><span><span>    <span>    if sock == server:</span></span><br/></span></div><div><span><span>    <span>    <span>    sonn, addr = server.accept()</span></span></span><br/></span></div><div><span><span>    <span>    <span>    # select 监听的socket</span></span></span><br/></span></div><div><span><span>    <span>    <span>    inputs.append(conn)</span></span></span><br/></span></div><div><span><span>    <span>    elif sock == sys.stdin:</span></span><br/></span></div><div><span><span>    <span>    <span>    junk = sys.stdin.readlines()</span></span></span><br/></span></div><div><span><span>    <span>    <span>    running = False</span></span></span><br/></span></div><div><span><span>    <span>    else:</span></span><br/></span></div><div><span><span>    <span>    <span>    try:</span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    # 读取客户端连接发送的数据</span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    data = sock.recv(BUFFER_SIZE)</span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    if data:</span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    <span>    sock.send(data)</span></span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    <span>    if data.endswith('\r\n\r\n'):</span></span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    <span>    <span>    # 移除select监听的socket</span></span></span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    <span>    <span>    inputs.remove(sock)</span></span></span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    <span>    <span>    sock.close()</span></span></span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    </span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    else:</span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    <span>    # 移除select监听的socket</span></span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    <span>    inputs.remove(sock)</span></span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    <span>    sock.close()</span></span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    except socket.error, e:</span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    inputs.remove(sock)</span></span></span></span><br/></span></div><div><span><br/></span></div><div><span>server.close()</span></div><div><br/></div><div><br/></div><div><br/></div></div><div><br/></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>inputs = [server, sys.stdin]</div></div><div>这里定义了一个需要select监听的列表，列表里面是需要监听的对象（等于系统监听的文件描述符）。这里监听socket套接字和用户的输入。</div><div><br/></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">try:</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    # 调用 select 函数，阻塞等待</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    readable, writeable, exceptional = select.select(inputs, [], [])</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">except select.error, e:</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    break</span></div></div><div>客户端输入curl <a href="http://localhost:5000/">http://localhost:5000</a>之后，一个套接字通信开始，此时input中的第一个对象server由不可用变成可用。因此select函数调用返回，此时的readable有一个套接字对象（文件描述符可读）。</div><div><br/></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">for sock in readable:</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    # 建立连接</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    if sock == server:</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">        conn, addr = server.accept()</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">        # select 监听的socket</span></div><div style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">        inputs.append(conn)</span></div></div><div>select返回之后，接下来遍历可读的文件对象，此时的可读中只有一个套接字连接，调用套接字的accept()方法建立TCP三次握手的连接，<font style="font-size: 14pt; color: rgb(173, 0, 0);"><b>然后把该连接对象追加到inputs监视列表中，表示我们要监视该连接是否有数据IO操作</b></font>。</div><div><br/></div><div>由于此时readable只有一个可用的对象，因此遍历结束。再回到主循环，再次调用select，此时调用的时候，<font style="font-size: 12pt; color: rgb(173, 0, 0);"><b>不仅会遍历监视是否有新的连接需要建立</b></font>，还是<font style="font-size: 14pt; color: rgb(173, 0, 0);"><b>监视刚才追加的连接</b></font>。如果curl的数据到了，select再返回到readable，此时在进行for循环。如果没有新的套接字，将会执行下面的代码：</div><div><br/></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>try:</div><div>    # 读取客户端连接发送的数据</div><div>    data = sock.recv(BUFFER_SIZE)</div><div>    if data:</div><div>        sock.send(data)</div><div>        if data.endswith('rnrn'):</div><div>            # 移除select监听的socket</div><div>            inputs.remove(sock)</div><div>            sock.close()</div><div>    else:</div><div>        # 移除select监听的socket</div><div>        inputs.remove(sock)</div><div>        sock.close()</div><div>except socket.error, e:</div><div>    inputs.remove(sock)</div></div><div>通过套接字连接调用recv函数，获取客户端发送的数据，当数据传输完毕，再把监视的inputs列表中除去该连接。然后关闭连接。</div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><font color="#1C3387" style="font-size: 18pt;"><b>epoll模式</b></font></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">#!/usr/bin/env python  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">import select  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">import socket  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">response = b''  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">serversocket.bind(('0.0.0.0', 8080))  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">serversocket.listen(1)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"># 因为socket默认是阻塞的，所以需要使用非阻塞（异步）模式。  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">serversocket.setblocking(0)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"># 创建一个epoll对象  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">epoll = select.epoll()  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"># 在服务端socket上面注册对读event的关注。一个读event随时会触发服务端socket去接收一个socket连接  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">epoll.register(serversocket.fileno(), select.EPOLLIN)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">try:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    # 字典connections映射文件描述符（整数）到其相应的网络连接对象  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    connections = {}  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    requests = {}  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    responses = {}  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    while True:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">        # 查询epoll对象，看是否有任何关注的event被触发。参数“1”表示，我们会等待1秒来看是否有event发生。  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">        # 如果有任何我们感兴趣的event发生在这次查询之前，这个查询就会带着这些event的列表立即返回  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">        events = epoll.poll(1)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">        # event作为一个序列（fileno，event code）的元组返回。fileno是文件描述符的代名词，始终是一个整数。  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">        for fileno, event in events:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            # 如果是服务端产生event,表示有一个新的连接进来  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            if fileno == serversocket.fileno():  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                connection, address = serversocket.accept()  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                print('client connected:', address)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                # 设置新的socket为非阻塞模式  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                connection.setblocking(0)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                # 为新的socket注册对读（EPOLLIN）event的关注  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                epoll.register(connection.fileno(), select.EPOLLIN)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                connections[connection.fileno()] = connection  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                # 初始化接收的数据  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                requests[connection.fileno()] = b''  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            # 如果发生一个读event，就读取从客户端发送过来的新数据  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            elif event &amp; select.EPOLLIN:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                print(&quot;------recvdata---------&quot;)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                # 接收客户端发送过来的数据  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                requests[fileno] += connections[fileno].recv(1024)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                # 如果客户端退出,关闭客户端连接，取消所有的读和写监听  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                if not requests[fileno]:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    connections[fileno].close()  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    # 删除connections字典中的监听对象  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    del connections[fileno]  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    # 删除接收数据字典对应的句柄对象  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    del requests[connections[fileno]]  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    print(connections, requests)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    epoll.modify(fileno, 0)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                else:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    # 一旦完成请求已收到，就注销对读event的关注，注册对写（EPOLLOUT）event的关注。写event发生的时候，会回复数据给客户端  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    epoll.modify(fileno, select.EPOLLOUT)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    # 打印完整的请求，证明虽然与客户端的通信是交错进行的，但数据可以作为一个整体来组装和处理  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    print('-' * 40 + '\n' + requests[fileno].decode())  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            # 如果一个写event在一个客户端socket上面发生，它会接受新的数据以便发送到客户端  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            elif event &amp; select.EPOLLOUT:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                print(&quot;-------send data---------&quot;)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                # 每次发送一部分响应数据，直到完整的响应数据都已经发送给操作系统等待传输给客户端  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                byteswritten = connections[fileno].send(requests[fileno])  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                requests[fileno] = requests[fileno][byteswritten:]  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                if len(requests[fileno]) == 0:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    # 一旦完整的响应数据发送完成，就不再关注写event  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                    epoll.modify(fileno, select.EPOLLIN)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            # HUP（挂起）event表明客户端socket已经断开（即关闭），所以服务端也需要关闭。  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            # 没有必要注册对HUP event的关注。在socket上面，它们总是会被epoll对象注册  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">            elif event &amp; select.EPOLLHUP:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                print(&quot;end hup------&quot;)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                # 注销对此socket连接的关注  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                epoll.unregister(fileno)  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                # 关闭socket连接  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                connections[fileno].close()  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">                del connections[fileno]  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">finally:  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    # 打开的socket连接不需要关闭，因为Python会在程序结束的时候关闭。这里显式关闭是一个好的代码习惯  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    epoll.unregister(serversocket.fileno())  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    epoll.close()  </span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">    serversocket.close()</span></div></div><div><br/></div><div><br/></div></div></span>
</div></body></html> 